<template>
  <view class="fu-calendar">
    <fu-popup
      v-model:show="localVisible"
      position="bottom"
      :close-on-click-overlay="closeOnClickOverlay"
      @click-overlay="onCancel"
    >
      <!-- 标题栏 -->
      <view class="fu-calendar__header">
        <text 
          class="fu-calendar__cancel"
          @click="onCancel"
        >取消</text>
        <text class="fu-calendar__title">{{ title }}</text>
        <text 
          class="fu-calendar__confirm"
          @click="onConfirm"
        >确定</text>
      </view>
      
      <!-- 星期栏 -->
      <view class="fu-calendar__week">
        <text 
          v-for="(item, index) in weekdays" 
          :key="index"
          class="fu-calendar__weekday"
        >{{ item }}</text>
      </view>
      
      <!-- 日期面板 -->
      <scroll-view
        scroll-y
        class="fu-calendar__body"
        :scroll-with-animation="true"
        :show-scrollbar="false"
        @touchmove.stop.prevent="() => {}"
      >
        <view 
          v-for="(month, index) in months"
          :key="index"
          class="fu-calendar__month"
        >
          <!-- 月份标题 -->
          <view class="fu-calendar__month-title">
            {{ month.title }}
          </view>
          
          <!-- 日期格子 -->
          <view class="fu-calendar__days">
            <view
              v-for="(day, idx) in month.days"
              :key="idx"
              class="fu-calendar__day"
              :class="{
                'fu-calendar__day--disabled': day.disabled,
                'fu-calendar__day--selected': isSelected(day) && !isMiddleDay(day),
                'fu-calendar__day--start': isStartDay(day),
                'fu-calendar__day--end': isEndDay(day),
                'fu-calendar__day--middle': isMiddleDay(day)
              }"
              @click="onClickDay(day)"
            >
              <text 
                class="fu-calendar__day-num"
                :class="{ 'is-selected': isSelected(day) }"
              >{{ day.date }}</text>
              <text 
                v-if="day.bottomInfo"
                class="fu-calendar__day-info"
                :class="{ 'is-selected': isSelected(day) }"
              >{{ day.bottomInfo }}</text>
            </view>
          </view>
        </view>
      </scroll-view>
    </fu-popup>
  </view>
</template>

<script>
/**
 * fu-calendar 日历组件
 * @description 日历组件，支持单选、多选、范围选择
 * @property {Boolean} show - 是否显示日历
 * @property {String} title - 日历标题
 * @property {String} type - 选择类型，可选值：single/multiple/range
 * @property {Array} value - 选中值，日期字符串数组
 * @property {String} minDate - 最小日期，格式为 YYYY-MM-DD
 * @property {String} maxDate - 最大日期，格式为 YYYY-MM-DD
 * @property {Boolean} showSubtitle - 是否展示日期标题
 * @property {Function} formatter - 日期格式化函数
 * @property {Boolean} closeOnClickOverlay - 是否点击遮罩层后关闭
 * @event {Function} confirm - 点击确定按钮时触发
 * @event {Function} cancel - 点击取消按钮时触发
 * @event {Function} select - 点击日期时触发
 */
export default {
  name: 'fu-calendar',
  props: {
    show: {
      type: Boolean,
      default: false
    },
    title: {
      type: String,
      default: '日期选择'
    },
    type: {
      type: String,
      default: 'single',
      validator: value => ['single', 'multiple', 'range'].includes(value)
    },
    value: {
      type: Array,
      default: () => []
    },
    minDate: {
      type: String,
      default: ''
    },
    maxDate: {
      type: String,
      default: ''
    },
    showSubtitle: {
      type: Boolean,
      default: true
    },
    formatter: {
      type: Function,
      default: null
    },
    closeOnClickOverlay: {
      type: Boolean,
      default: false
    }
  },
  emits: ['update:show', 'confirm', 'cancel', 'select'],
  data() {
    return {
      localVisible: false,
      currentDate: [],
      tempDate: [],
      weekdays: ['日', '一', '二', '三', '四', '五', '六'],
      months: []
    }
  },
  watch: {
    show: {
      handler(val) {
        this.localVisible = val
        if (val) {
          this.initMonths()
          this.tempDate = [...this.currentDate]
        }
      },
      immediate: true
    },
    value: {
      handler(val) {
        this.currentDate = [...val]
        this.tempDate = [...val]
      },
      immediate: true
    },
    localVisible(val) {
      this.$emit('update:show', val)
    }
  },
  methods: {
    // 初始化月份数据
    initMonths() {
      const months = []
      const start = this.minDate ? new Date(this.minDate) : new Date()
      const end = this.maxDate ? new Date(this.maxDate) : new Date(start.getFullYear(), start.getMonth() + 6, 0)
      
      let current = new Date(start)
      while (current <= end) {
        const year = current.getFullYear()
        const month = current.getMonth()
        
        // 生成月份数据
        const monthData = {
          title: `${year}年${month + 1}月`,
          days: this.getDays(year, month)
        }
        
        months.push(monthData)
        current = new Date(year, month + 1, 1)
      }
      
      this.months = months
    },
    
    // 获取某月的所有日期
    getDays(year, month) {
      const days = []
      const firstDay = new Date(year, month, 1)
      const lastDay = new Date(year, month + 1, 0)
      const total = lastDay.getDate()
      
      // 补充上月空白
      const weekday = firstDay.getDay()
      for (let i = 0; i < weekday; i++) {
        days.push({ type: 'disabled' })
      }
      
      // 生成当月日期
      for (let i = 1; i <= total; i++) {
        const date = new Date(year, month, i)
        const dateStr = this.formatDate(date)
        const disabled = this.isDisabled(date)
        
        const dayData = {
          date: i,
          type: 'normal',
          dateStr,
          disabled
        }
        
        // 自定义格式化
        if (this.formatter) {
          Object.assign(dayData, this.formatter(dayData))
        }
        
        days.push(dayData)
      }
      
      return days
    },
    
    // 格式化日期
    formatDate(date) {
      const year = date.getFullYear()
      const month = String(date.getMonth() + 1).padStart(2, '0')
      const day = String(date.getDate()).padStart(2, '0')
      return `${year}-${month}-${day}`
    },
    
    // 判断日期是否禁用
    isDisabled(date) {
      const min = this.minDate ? new Date(this.minDate) : null
      const max = this.maxDate ? new Date(this.maxDate) : null
      
      if (min && date < min) return true
      if (max && date > max) return true
      return false
    },
    
    // 判断是否选中
    isSelected(day) {
      if (!day.dateStr) return false
      return this.tempDate.includes(day.dateStr)
    },
    
    // 判断是否为起始日期
    isStartDay(day) {
      if (this.type !== 'range' || !day.dateStr) return false
      return day.dateStr === this.tempDate[0]
    },
    
    // 判断是否为结束日期
    isEndDay(day) {
      if (this.type !== 'range' || !day.dateStr) return false
      return day.dateStr === this.tempDate[1]
    },
    
    // 判断是否为范围中间日期
    isMiddleDay(day) {
      if (this.type !== 'range' || !day.dateStr || this.tempDate.length !== 2) return false
      const [start, end] = this.tempDate
      return day.dateStr > start && day.dateStr < end
    },
    
    // 点击日期
    onClickDay(day) {
      if (day.disabled || !day.dateStr) return
      
      const date = day.dateStr
      let newDates = []
      
      switch (this.type) {
        case 'single':
          newDates = [date]
          break
          
        case 'multiple':
          newDates = this.tempDate.includes(date)
            ? this.tempDate.filter(d => d !== date)
            : [...this.tempDate, date]
          break
          
        case 'range':
          if (this.tempDate.length === 2) {
            newDates = [date]
          } else {
            const [start] = this.tempDate
            newDates = date < start ? [date, start] : [start, date]
          }
          break
      }
      
      this.tempDate = newDates
      this.$emit('select', newDates)
    },
    
    // 确认选择
    onConfirm() {
      this.currentDate = [...this.tempDate]
      this.$emit('confirm', this.currentDate)
      this.localVisible = false
    },
    
    // 取消选择
    onCancel() {
      this.tempDate = [...this.currentDate]
      this.$emit('cancel')
      this.localVisible = false
    },
    
    // 点击遮罩层
    onClickOverlay() {
      if (this.closeOnClickOverlay) {
        this.onCancel()
      }
    }
  }
}
</script>

<style lang="scss" scoped>
.fu-calendar {
  &__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    height: 88rpx;
    padding: 0 30rpx;
    background-color: #f7f8fa;
  }
  
  &__title {
    font-size: var(--fu-font-size-lg);
    color: var(--fu-text-color);
    font-weight: 500;
  }
  
  &__cancel,
  &__confirm {
    padding: 16rpx;
    font-size: var(--fu-font-size-base);
    color: var(--fu-text-color-secondary);
    
    &:active {
      opacity: 0.7;
    }
  }
  
  &__confirm {
    color: var(--fu-primary-color);
  }
  
  &__week {
    display: flex;
    padding: 16rpx 0;
    background-color: #fff;
  }
  
  &__weekday {
    flex: 1;
    text-align: center;
    font-size: var(--fu-font-size-sm);
    color: var(--fu-text-color-secondary);
  }
  
  &__body {
    height: 800rpx;
    background-color: #fff;
    -webkit-overflow-scrolling: touch;
  }
  
  &__month {
    padding: 0 16rpx;
  }
  
  &__month-title {
    padding: 30rpx 0 16rpx;
    font-size: var(--fu-font-size-lg);
    font-weight: 500;
    color: var(--fu-text-color);
    text-align: center;
  }
  
  &__days {
    display: flex;
    flex-wrap: wrap;
  }
  
  &__day {
    position: relative;
    width: calc(100% / 7);
    height: 120rpx;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    transition: background-color 0.2s;
    
    &--disabled {
      color: var(--fu-text-color-disabled);
      cursor: not-allowed;
      opacity: 0.4;
    }
    
    &--selected {
      background-color: var(--fu-primary-color);
      border-radius: 8rpx;
      
      .fu-calendar__day-num,
      .fu-calendar__day-info.is-selected {
        color: #fff;
      }
    }
    
    &--start,
    &--end {
      background-color: var(--fu-primary-color);
      color: #fff;
      z-index: 1;
      position: relative;
      
      &::after {
        content: '';
        position: absolute;
        top: 0;
        bottom: 0;
        width: 50%;
        background-color: var(--fu-primary-color-light);
      }
    }
    
    &--start {
      border-radius: 8rpx 0 0 8rpx;
      
      &::after {
        right: 0;
      }
    }
    
    &--end {
      border-radius: 0 8rpx 8rpx 0;
      
      &::after {
        left: 0;
      }
    }
    
    &--middle {
      background-color: var(--fu-primary-color-light);
      color: var(--fu-primary-color);
      position: relative;
      z-index: 0;
      
      .fu-calendar__day-info {
        color: var(--fu-primary-color);
      }
      
      &:hover {
        background-color: var(--fu-primary-color-lighter);
      }
    }
    
    &:not(.fu-calendar__day--disabled):active {
      opacity: 0.8;
    }
  }
  
  &__day-num {
    font-size: var(--fu-font-size-lg);
    line-height: 1.2;
    transition: color 0.2s;
    position: relative;
    z-index: 1;
    
    &.is-selected {
      color: #fff;
    }
  }
  
  &__day-info {
    font-size: var(--fu-font-size-sm);
    color: var(--fu-text-color-secondary);
    margin-top: 4rpx;
    transition: color 0.2s;
    position: relative;
    z-index: 1;
    
    &.is-selected {
      color: #fff;
    }
  }
}
</style> 